package com.atguigu.tingshu.common.login;

import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.user.UserInfo;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @Author 快点干早点散
 * @Create 2025/6/25 15:45
 * Description:
 */

@Component
@Aspect
@Slf4j
public class TsLoginAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @Around("@annotation(tsLogin)")
    public Object around(ProceedingJoinPoint point, TsLogin tsLogin) throws Throwable {
        //ProceedingJoinPoint 切点的类 获取方法请求 参数返回值 和方法体运行期间 都可以取
        /*
         登录拦截功能
         登录业务:
         1.当登录成功之后,会将token 写入请求头; 判断里面是否有token
         2.效验成功之后,会将用户信息存到缓存中
      */
        //1. 先获取请求头对象,在从头里获取token
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        //  转化为ServletRequestAttributes
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) previousAttributes;
        //  获取到HttpServletRequest 对象
        HttpServletRequest request = servletRequestAttributes.getRequest();

        String token = request.getHeader("token");
        //获取注解属性
        //        MethodSignature signature = (MethodSignature) point.getSignature();
        //        TsLogin tsLogin = signature.getMethod().getAnnotation(TsLogin.class);
        //        boolean required = tsLogin.required();
        boolean required = tsLogin.required();
        if (required) {
            //需要登录
            if (StringUtils.isEmpty(token)) {
                //抛出异常
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //获取缓存信息 判断是否有缓存信息
            String userLoginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
            UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(userLoginKey);
            //判断对象是否为空
            if (null == userInfo) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
        }
        //token存在不为空
        if (!StringUtils.isEmpty(token)) {
            //获取缓存数据
            String userLoginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
            UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(userLoginKey);
            //获取用户对象是否为空;说明登录过
            if (null != userInfo) {
                //可以获取用户id 便于后续使用用户id 进行后续操作
                AuthContextHolder.setUserId(userInfo.getId());
                AuthContextHolder.setUsername(userInfo.getNickname());
            }
        }
        Object proceed = null;
        try {
            proceed = point.proceed();
        } catch (Exception e) {
            log.error("【登录拦截】异常：{}", e.getMessage());
        } finally {//删除防止内存溢出 OOM
            AuthContextHolder.removeUserId();
            AuthContextHolder.removeUsername();
        }

        //返回执行体方法体
        return proceed;
    }
}
